/** * */ package net.sf.commons.ssh.common; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.DSAPublicKeySpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.RSAPublicKeySpec; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.VFS; import org.bouncycastle.openssl.PEMReader; import org.bouncycastle.openssl.PEMWriter; import org.bouncycastle.openssl.PasswordFinder; /** * @author fob * @date 14.08.2011 * @since 2.0 */ public class KeyUtils { public static PublicKey getKeyFromBase64(byte[] keyBytes) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException { return getKeyFromBytes(Base64.decodeBase64(keyBytes)); } public static PublicKey getKeyFromBytes(byte[] keyBytes) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException { DataInputStream keyData = new DataInputStream(new ByteArrayInputStream(keyBytes)); int length = keyData.readInt(); String alg = new String(readBytes(keyData, length)); alg = StringUtils.substringAfter(alg, "-").toLowerCase(); if ("dss".equals(alg)) alg = "dsa"; KeyFactory keyFactory = KeyFactory.getInstance(alg.toUpperCase()); KeySpec spec; if ("rsa".equals(alg)) { length = keyData.readInt(); BigInteger e = readBigInteger(length, keyData); length = keyData.readInt(); BigInteger m = readBigInteger(length, keyData); spec = new RSAPublicKeySpec(m, e); } else { length = keyData.readInt(); BigInteger p = readBigInteger(length, keyData); length = keyData.readInt(); BigInteger q = readBigInteger(length, keyData); length = keyData.readInt(); BigInteger g = readBigInteger(length, keyData); length = keyData.readInt(); BigInteger y = readBigInteger(length, keyData); spec = new DSAPublicKeySpec(y, p, q, g); } return keyFactory.generatePublic(spec); } public static PublicKey getKeyFromBase64(String keyBytes) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException { return getKeyFromBase64(keyBytes.getBytes()); } public static String encodeKeyToBase64(PublicKey publicKey) { ByteArrayOutputStream keyBytes = new ByteArrayOutputStream(); DataOutputStream keyData = new DataOutputStream(keyBytes); try { if (publicKey instanceof RSAPublicKey) { keyData.writeInt("ssh-rsa".length()); keyData.write("ssh-rsa".getBytes()); BigInteger e = ((RSAPublicKey) publicKey).getPublicExponent(); keyData.writeInt(e.toByteArray().length); keyData.write(e.toByteArray()); BigInteger m = ((RSAPublicKey) publicKey).getModulus(); keyData.writeInt(m.toByteArray().length); keyData.write(m.toByteArray()); keyData.close(); } else { keyData.writeInt("ssh-dss".length()); keyData.write("ssh-dss".getBytes()); BigInteger p = ((DSAPublicKey) publicKey).getParams().getP(); BigInteger g = ((DSAPublicKey) publicKey).getParams().getG(); BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ(); BigInteger y = ((DSAPublicKey) publicKey).getY(); keyData.writeInt(p.toByteArray().length); keyData.write(p.toByteArray()); keyData.writeInt(q.toByteArray().length); keyData.write(q.toByteArray()); keyData.writeInt(g.toByteArray().length); keyData.write(g.toByteArray()); keyData.writeInt(y.toByteArray().length); keyData.write(y.toByteArray()); } } catch (IOException e) { throw new RuntimeException("unexpected IO exception", e); } return new String(Base64.encodeBase64(keyBytes.toByteArray())); } public static PublicKey getKeyFromPubFile(Reader reader) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException { BufferedReader bReader = new BufferedReader(reader); String line = bReader.readLine(); line = StringUtils.substringAfter(line, " "); line = StringUtils.substringBefore(line, " "); return getKeyFromBase64(line.getBytes()); } public static PublicKey getKeyFromPubFile(InputStream stream) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException { return getKeyFromPubFile(new InputStreamReader(stream)); } public static PublicKey getKeyFromPubFile(String file) throws InvalidKeySpecException, IOException, NoSuchAlgorithmException { FileObject fileObject = VFS.getManager().resolveFile(new File("."), file); InputStream st = fileObject.getContent().getInputStream(); try { return getKeyFromPubFile(st); } finally { IOUtils.close(st); } } public static KeyPair getPrivateKeyFromStream(InputStream stream, final String passphrase) throws IOException { PEMReader reader; if (passphrase == null) reader = new PEMReader(new InputStreamReader(stream)); else reader = new PEMReader(new InputStreamReader(stream), new PasswordFinder() { @Override public char[] getPassword() { return passphrase.toCharArray(); } }); return (KeyPair) reader.readObject(); } public static KeyPair getPrivateKeyFromBytes(byte[] bytes, String passphrase) throws IOException { return getPrivateKeyFromStream(new ByteArrayInputStream(bytes), passphrase); } public static KeyPair getPrivateKeyFromFile(String file, String passphrase) throws IOException { FileObject fileObject = VFS.getManager().resolveFile(new File("."), file); InputStream st = fileObject.getContent().getInputStream(); try { return getPrivateKeyFromStream(st, passphrase); } finally { IOUtils.close(st); } } protected static byte[] readBytes(InputStream stream, int len) throws IOException { byte[] buffer = new byte[len]; stream.read(buffer); return buffer; } private static BigInteger readBigInteger(int length, InputStream stream) throws IOException { byte[] buffer = new byte[length]; stream.read(buffer); return new BigInteger(buffer); } public static byte[] serializePrivateKey(PrivateKey key) throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); serializePrivateKey(key, new OutputStreamWriter(stream)); return stream.toByteArray(); } public static void serializePrivateKey(PrivateKey key, Writer writer) throws IOException { PEMWriter pemWriter = new PEMWriter(writer); pemWriter.writeObject(key); pemWriter.flush(); } public static void serializePrivateKey(PrivateKey key, Writer writer,char[] password,String alg) throws IOException { PEMWriter pemWriter = new PEMWriter(writer); pemWriter.writeObject(key,alg,password,new SecureRandom()); pemWriter.flush(); } }